package com.example.dictionary.service;

import com.example.dictionary.config.DictionaryProperties;
import com.example.dictionary.service.DownloadPathMappingService;
import com.example.dictionary.util.DiskSpaceUtil;
import com.example.memento.download.service.DownloadService;
import com.example.memento.model.ApiResponse;
import com.example.memento.model.DictionarySource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * GitHub 仓库下载服务
 * 支持 Git URL 转换为 ZIP URL 并下载
 */
@Service
public class GithubDownloadService {
    
    private static final Logger log = LoggerFactory.getLogger(GithubDownloadService.class);
    
    // 匹配 GitHub Git URL 格式
    // https://github.com/owner/repo.git
    // https://github.com/owner/repo
    // git@github.com:owner/repo.git
    private static final Pattern GITHUB_GIT_URL_PATTERN = Pattern.compile(
        "(?:https?://)?(?:git@)?github\\.com[:/]([^/]+)/([^/\\.]+)(?:\\.git)?(?:/.*)?$"
    );
    
    private static final String DEFAULT_DOWNLOAD_PATH = "data/res";
    private static final String DEFAULT_DOMAIN_PATH = "data/res";
    
    private final DownloadService downloadService;
    private final DictionaryProperties dictionaryProperties;
    private final DownloadPathMappingService downloadPathMappingService;
    
    public GithubDownloadService(DownloadService downloadService, 
                                DictionaryProperties dictionaryProperties,
                                DownloadPathMappingService downloadPathMappingService) {
        this.downloadService = downloadService;
        this.dictionaryProperties = dictionaryProperties;
        this.downloadPathMappingService = downloadPathMappingService;
    }
    
    /**
     * 下载 DomainWordsDict 仓库（支持字符串路径参数）
     * 
     * @param targetDir 目标目录字符串（可选，如果为 null 或空则从配置读取或使用默认路径）
     * @param extract 是否解压，默认为 true
     * @return 下载结果
     */
    public ApiResponse<Map<String, Object>> downloadDomainWordsDict(
            String targetDir, boolean extract) {
        String gitUrl = "https://github.com/liuhuanyong/DomainWordsDict.git";
        
        // 调用 downloadRepository 方法，传入字符串参数，让服务层处理所有业务逻辑
        return downloadRepository(gitUrl, "master", targetDir, extract);
    }
    
    /**
     * 下载 DomainWordsDict 仓库（使用 Path 参数，兼容旧代码）
     * 
     * @param targetDir 目标目录（可选，如果为 null 则从配置读取或使用默认路径）
     * @param extract 是否解压，默认为 true
     * @return 下载结果
     * @deprecated 使用 {@link #downloadDomainWordsDict(String, boolean)} 方法
     */
    @Deprecated
    public ApiResponse<Map<String, Object>> downloadDomainWordsDict(
            Path targetDir, boolean extract) {
        String targetDirStr = targetDir != null ? targetDir.toString() : null;
        return downloadDomainWordsDict(targetDirStr, extract);
    }
    
    /**
     * 从全局配置中获取保存路径列表
     * 
     * @return 保存路径列表，如果配置中未指定则返回空列表
     */
    public List<Path> getSavePathsFromConfig() {
        if (dictionaryProperties == null || dictionaryProperties.getDownload() == null) {
            return List.of();
        }
        
        String savePathStr = dictionaryProperties.getDownload().getSavePath();
        if (savePathStr == null || savePathStr.trim().isEmpty()) {
            return List.of();
        }
        
        return DiskSpaceUtil.parsePaths(savePathStr);
    }
    
    /**
     * 从配置中获取指定词典源的保存路径列表（兼容旧代码）
     * 
     * @param sourceName 词典源名称（已废弃，不再使用）
     * @return 保存路径列表，从全局配置获取
     * @deprecated 使用 {@link #getSavePathsFromConfig()} 方法
     */
    @Deprecated
    public List<Path> getSavePathsFromConfig(String sourceName) {
        return getSavePathsFromConfig();
    }
    
    /**
     * 根据 Git URL 从配置中获取保存路径列表（兼容旧代码）
     * 
     * @param gitUrl Git URL（已废弃，不再使用）
     * @return 保存路径列表，从全局配置获取
     * @deprecated 使用 {@link #getSavePathsFromConfig()} 方法
     */
    @Deprecated
    public List<Path> getSavePathsByUrl(String gitUrl) {
        return getSavePathsFromConfig();
    }
    
    /**
     * 从配置中获取指定词典源的保存路径（单个路径，兼容旧代码）
     * 
     * @param sourceName 词典源名称
     * @return 保存路径，如果配置中未指定则返回空
     * @deprecated 使用 {@link #getSavePathsFromConfig(String)} 获取多个路径
     */
    @Deprecated
    public Optional<String> getSavePathFromConfig(String sourceName) {
        List<Path> paths = getSavePathsFromConfig(sourceName);
        if (paths.isEmpty()) {
            return Optional.empty();
        }
        return Optional.of(paths.get(0).toString());
    }
    
    /**
     * 根据 Git URL 从配置中获取保存路径（单个路径，兼容旧代码）
     * 
     * @param gitUrl Git URL
     * @return 保存路径，如果配置中未指定则返回空
     * @deprecated 使用 {@link #getSavePathsByUrl(String)} 获取多个路径
     */
    @Deprecated
    public Optional<String> getSavePathByUrl(String gitUrl) {
        List<Path> paths = getSavePathsByUrl(gitUrl);
        if (paths.isEmpty()) {
            return Optional.empty();
        }
        return Optional.of(paths.get(0).toString());
    }
    
    /**
     * 选择最佳的下载路径（检查磁盘空间并随机选择）
     * 
     * @param paths 路径列表（从配置获取）
     * @param defaultPath 默认路径（如果配置的路径都不可用）
     * @return 选择的路径
     */
    private Path selectBestDownloadPath(List<Path> paths, Path defaultPath) {
        if (paths == null || paths.isEmpty()) {
            log.info("使用默认下载路径: {}", defaultPath);
            return defaultPath;
        }
        
        // 检查磁盘空间并选择最佳路径
        Optional<Path> selectedPath = DiskSpaceUtil.selectPathWithSpace(paths);
        return selectedPath.orElse(defaultPath);
    }
    
    /**
     * 解析目标路径（从字符串或全局配置中获取）
     * 
     * @param targetDir 目标目录字符串（可选）
     * @param identifier 标识符（已废弃，保留用于兼容性）
     * @param defaultPathStr 默认路径字符串
     * @return 解析后的路径
     */
    private Path resolveTargetPath(String targetDir, String identifier, String defaultPathStr) {
        // 如果指定了目标目录，直接使用
        if (targetDir != null && !targetDir.trim().isEmpty()) {
            Path targetPath = Path.of(targetDir.trim());
            log.info("使用指定的目标目录: {}", targetPath);
            return targetPath;
        }
        
        // 从全局配置中获取路径
        List<Path> configPaths = getSavePathsFromConfig();
        
        // 选择最佳路径或使用默认路径
        Path defaultPath = Path.of(defaultPathStr);
        if (configPaths.isEmpty()) {
            log.info("未找到全局配置路径，使用默认路径: {}", defaultPath);
            return defaultPath;
        } else {
            Path selectedPath = selectBestDownloadPath(configPaths, defaultPath);
            log.info("从全局配置路径中选择: {}", selectedPath);
            return selectedPath;
        }
    }
    
    /**
     * 下载 GitHub 仓库（支持字符串参数，包含完整业务逻辑）
     * 
     * @param gitUrl GitHub Git URL（必填）
     * @param branch 分支名称（可选，默认为 master）
     * @param targetDir 目标目录字符串（可选，如果为 null 或空则从配置读取或使用默认路径）
     * @param extract 是否解压（可选，默认为 true）
     * @return 下载结果
     */
    public ApiResponse<Map<String, Object>> downloadRepository(
            String gitUrl, String branch, String targetDir, Boolean extract) {
        // 参数验证
        if (gitUrl == null || gitUrl.trim().isEmpty()) {
            return ApiResponse.<Map<String, Object>>builder()
                    .success(false)
                    .message("GitHub URL 不能为空")
                    .data(null)
                    .build();
        }
        
        // URL 格式验证
        if (!isValidGithubUrl(gitUrl)) {
            return ApiResponse.<Map<String, Object>>builder()
                    .success(false)
                    .message("无效的 GitHub URL: " + gitUrl)
                    .data(null)
                    .build();
        }
        
        // 处理分支：默认值为 master
        String actualBranch = (branch != null && !branch.trim().isEmpty()) ? branch.trim() : "master";
        
        // 处理解压参数：默认值为 true
        boolean actualExtract = extract != null ? extract : true;
        
        // 处理目标目录：转换为 Path 或从配置选择
        Path targetPath = resolveTargetPath(targetDir, gitUrl, DEFAULT_DOWNLOAD_PATH);
        
        log.info("开始下载 GitHub 仓库: {}, 分支: {}, 目标目录: {}, 解压: {}",
                gitUrl, actualBranch, targetPath, actualExtract);
        
        return downloadRepositoryWithPath(gitUrl, actualBranch, targetPath, actualExtract);
    }
    
    /**
     * 下载 GitHub 仓库（使用 Path 参数，兼容旧代码）
     * 
     * @param gitUrl GitHub Git URL
     * @param branch 分支名称，默认为 master
     * @param targetDir 目标目录（可选，如果为 null 则从配置读取或使用默认路径）
     * @param extract 是否解压
     * @return 下载结果
     * @deprecated 使用 {@link #downloadRepository(String, String, String, Boolean)} 方法
     */
    @Deprecated
    public ApiResponse<Map<String, Object>> downloadRepository(
            String gitUrl, String branch, Path targetDir, boolean extract) {
        String targetDirStr = targetDir != null ? targetDir.toString() : null;
        String actualBranch = (branch != null && !branch.trim().isEmpty()) ? branch.trim() : "master";
        return downloadRepository(gitUrl, actualBranch, targetDirStr, extract);
    }
    
    /**
     * 下载 GitHub 仓库（通过 ZIP 方式）
     * 
     * @param gitUrl GitHub Git URL，如 https://github.com/liuhuanyong/DomainWordsDict.git
     * @param branch 分支名称，默认为 master
     * @param targetDir 目标目录
     * @param extract 是否解压
     * @return 下载结果
     */
    private ApiResponse<Map<String, Object>> downloadRepositoryWithPath(
            String gitUrl, String branch, Path targetDir, boolean extract) {
        try {
            // 检查是否已有下载记录
            String resourceKey = downloadPathMappingService.buildGitHubResourceKey(gitUrl, branch);
            Optional<String> existingPath = downloadPathMappingService.getDownloadPath(resourceKey);
            
            if (existingPath.isPresent()) {
                Path existingPathObj = Paths.get(existingPath.get());
                if (Files.exists(existingPathObj)) {
                    log.info("发现已下载的资源，使用现有路径: {} -> {}", resourceKey, existingPath.get());
                    return ApiResponse.<Map<String, Object>>builder()
                            .success(true)
                            .message("使用已下载的资源")
                            .data(Map.of(
                                    "originalUrl", gitUrl,
                                    "savedDir", existingPath.get(),
                                    "fromCache", true,
                                    "extract", extract
                            ))
                            .build();
                } else {
                    log.warn("映射的路径不存在，将重新下载: {}", existingPath.get());
                    downloadPathMappingService.removeMapping(resourceKey);
                }
            }
            
            // 转换为 ZIP URL
            String zipUrl = convertGitUrlToZipUrl(gitUrl, branch);
            if (zipUrl == null) {
                return ApiResponse.<Map<String, Object>>builder()
                        .success(false)
                        .message("无效的 GitHub URL: " + gitUrl)
                        .data(null)
                        .build();
            }
            
            log.info("转换 GitHub URL: {} -> {}", gitUrl, zipUrl);
            
            // 下载并解压
            List<Path> files = downloadService.downloadAll(
                    List.of(zipUrl),
                    targetDir,
                    extract
            );
            
            // 确定实际保存的目录
            // 如果解压了，解压后的内容在 targetDir 下，需要找到解压后的根目录
            // 例如：targetDir/DomainWordsDict-master/
            String savedDir = targetDir.toAbsolutePath().toString();
            if (extract && !files.isEmpty() && Files.exists(targetDir)) {
                try {
                    // 尝试找到解压后的目录（通常是 ZIP 文件名去掉 .zip 后缀的目录）
                    // 例如：master.zip 解压后是 master/ 或 DomainWordsDict-master/
                    String zipFileName = files.get(0).getFileName().toString();
                    String extractedDirName = zipFileName.substring(0, zipFileName.lastIndexOf('.'));
                    
                    Path extractedDir = targetDir.resolve(extractedDirName);
                    if (Files.exists(extractedDir) && Files.isDirectory(extractedDir)) {
                        savedDir = extractedDir.toAbsolutePath().toString();
                        log.info("检测到解压后的目录: {}", savedDir);
                    } else {
                        // 如果没有找到预期的目录，尝试查找 targetDir 下的第一个目录
                        try (var stream = Files.list(targetDir)) {
                            var firstDir = stream
                                    .filter(Files::isDirectory)
                                    .findFirst();
                            if (firstDir.isPresent()) {
                                savedDir = firstDir.get().toAbsolutePath().toString();
                                log.info("使用解压后的第一个目录: {}", savedDir);
                            } else {
                                savedDir = targetDir.toAbsolutePath().toString();
                                log.info("未找到解压目录，使用目标目录: {}", savedDir);
                            }
                        }
                    }
                } catch (Exception e) {
                    log.warn("确定解压目录时出错，使用目标目录: {}", targetDir, e);
                    savedDir = targetDir.toAbsolutePath().toString();
                }
            }
            
            // 保存映射关系（下载成功后才保存）
            log.info("准备保存下载路径映射: {} -> {}", resourceKey, savedDir);
            downloadPathMappingService.saveMapping(resourceKey, savedDir);
            log.info("成功保存下载路径映射: {} -> {}", resourceKey, savedDir);
            
            return ApiResponse.<Map<String, Object>>builder()
                    .success(true)
                    .message("下载成功")
                    .data(Map.of(
                            "originalUrl", gitUrl,
                            "zipUrl", zipUrl,
                            "savedDir", savedDir,
                            "files", files.stream().map(p -> p.toAbsolutePath().toString()).toList(),
                            "extract", extract,
                            "fromCache", false
                    ))
                    .build();
        } catch (IOException e) {
            log.error("下载 GitHub 仓库失败: {}", gitUrl, e);
            return ApiResponse.<Map<String, Object>>builder()
                    .success(false)
                    .message("下载失败: " + e.getMessage())
                    .data(null)
                    .build();
        }
    }
    
    /**
     * 将 Git URL 转换为 ZIP 下载 URL
     * 
     * @param gitUrl Git URL
     * @param branch 分支名称
     * @return ZIP URL，如果转换失败返回 null
     */
    public String convertGitUrlToZipUrl(String gitUrl, String branch) {
        if (gitUrl == null || gitUrl.isEmpty()) {
            return null;
        }
        
        // 默认分支为 master
        if (branch == null || branch.isEmpty()) {
            branch = "master";
        }
        
        Matcher matcher = GITHUB_GIT_URL_PATTERN.matcher(gitUrl.trim());
        if (!matcher.find()) {
            log.warn("无法解析 GitHub URL: {}", gitUrl);
            return null;
        }
        
        String owner = matcher.group(1);
        String repo = matcher.group(2);
        
        // 构建 ZIP 下载 URL
        // https://github.com/owner/repo/archive/refs/heads/branch.zip
        String zipUrl = String.format(
                "https://github.com/%s/%s/archive/refs/heads/%s.zip",
                owner, repo, branch
        );
        
        return zipUrl;
    }
    
    /**
     * 检查是否为有效的 GitHub URL
     */
    public boolean isValidGithubUrl(String url) {
        if (url == null || url.isEmpty()) {
            return false;
        }
        return GITHUB_GIT_URL_PATTERN.matcher(url.trim()).matches();
    }
}

